package com.ruoyi.yys.util;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
import cn.hutool.http.HttpUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.aliyun.oss.*;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.GetObjectRequest;
import com.ruoyi.common.constant.ExcelStants;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.yys.common.enums.ErrorStatus;
import com.ruoyi.yys.domain.ImportExportTask;

import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Date;
import java.util.List;

/**
 * 注释
 *
 * @author lys
 * @date 2022/11/25
 */
public class OssUtils {
    private static final String endpoint = "oss-cn-beijing.aliyuncs.com";

    private static final String accessKeyId = "LTAI4GBQtRsvPrGVfZFJFPdA";

    private static final String accessKeySecret = "eqpMG0guPETaj1uh7s1uHhibIoQCZX";

    private static final String bucketName = "cfimagesserver";

    private static final String filePath = ExcelStants.EXCEL_PATH;

    public static void getOssPath(Entity entityById) {
        if (ObjectUtil.isEmpty(entityById) || !"export".equals(entityById.getStr("op_type"))) {
            return;
        }
        String op_file_name = entityById.getStr("op_file_name");
        if (StrUtil.isNotBlank(op_file_name)) {
            String filePath = OssUtils.getFileLink(op_file_name);
            entityById.set("op_down_path", filePath);
        }
    }

    public static void getOssPath(ImportExportTask task) {
        if (ObjectUtil.isEmpty(task) || !"export".equals(task.getOpType())) {
            return;
        }
        String ossPath = task.getOpFileName();
        if (StrUtil.isNotBlank(ossPath)) {
            String filePath = OssUtils.getFileLink(ossPath);
            task.setOpDownPath(filePath);
        }
    }

    /**
     * 删除存储在本地的图片文件
     */
    public static void delAllFile() {
        FileUtil.del(filePath);
    }

    /**
     * 将本地文件上传至阿里云oss
     *
     * @param file        文件流
     * @param ossFilePath 阿里云文件路径
     */
    public static void fileUpload(InputStream file, String ossFilePath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        ossClient.putObject(bucketName, ossFilePath, file);
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 将本地文件上传至阿里云oss
     *
     * @param filePath    本地文件路径
     * @param ossFilePath 阿里云文件路径
     */
    public static void fileUpload(String filePath, String ossFilePath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        try {
            InputStream fileInputStream = new FileInputStream(filePath);
            ossClient.putObject(bucketName, ossFilePath, fileInputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new ServiceException("上传OSS出错：" + e.getMessage());
        }
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 文件上传
     * 将本地文件上传至阿里云oss
     *
     * @param filePath    本地文件路径
     * @param ossFilePath 阿里云文件路径
     * @param isDelFile   是否删除文件
     */
    public static void fileUpload(String filePath, String ossFilePath, boolean isDelFile) {
        try {
            fileUpload(filePath, ossFilePath);
            //本地文件删除
            if (isDelFile) {
                FileUtil.del(filePath);
            }
        } catch (Exception e) {
            throw new com.ruoyi.common.exception.ServiceException(ErrorStatus.EXCEPTION.getCode(), "oss上传文件出错：" + e.getMessage());
        }
    }

    /**
     * 生成文件下载链接
     *
     * @param filepath oss文件路径
     * @return {@link String}
     */
    public static String getFileLink(String filepath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(bucketName, filepath, expiration);
        // 关闭OSSClient。
        ossClient.shutdown();
        return url.toString();
    }

    /**
     * inputstream 转 文件
     *
     * @param filepath filepath
     * @return {@link File}
     */
    public static File inputstreamToFile(String filepath) {
        InputStream picPathStream = getFileStream(filepath);
        File file = Opt.ofNullable(picPathStream).map(e -> {
            FileUtil.mkdir(filePath);
            String fileName = FileUtil.getName(filepath);
            //获取该文件的本地路径
            String path = filePath + "/" + fileName;
            return FileUtil.writeFromStream(picPathStream, path);
        }).orElse(null);
        return file;
    }

    /**
     * 删除oss一个文件
     *
     * @param filePath 填写文件完整路径。文件完整路径中不能包含Bucket名称。
     * @return boolean
     */
    public static boolean deleteFileOne(String filePath) {
        OSS ossClient = getOssClient();
        try {
            ossClient.deleteObject(bucketName, filePath);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return false;
        } finally {
            Opt.ofNullable(ossClient).ifPresent(e->e.shutdown());
        }
        return true;
    }

    /**
     * 删除oss多个文件
     *
     * @param filePaths 填写需要删除的多个文件完整路径。文件完整路径中不能包含Bucket名称。
     */
    public static void deleteFiles(List<String> filePaths) {
        OSS ossClient = getOssClient();
        try {
            DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(filePaths).withEncodingType("url"));
            List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
            try {
                for (String obj : deletedObjects) {
                    String deleteObj = URLDecoder.decode(obj, "UTF-8");
                    System.out.println(deleteObj);
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            Opt.ofNullable(ossClient).ifPresent(e->e.shutdown());
        }
    }

    /**
     * 得到oss连接
     *
     * @return {@link OSS}
     */
    private static OSS getOssClient() {
        return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }

    /**
     * 下载文件到本地
     *
     * @param filepath filepath
     * @return {@link String} 返回文件路径
     */
    public static String downloadFileNow(String filepath) {
        FileUtil.mkdir(filePath);
        String fileName = FileUtil.getName(filepath);
        //获取该文件的本地路径
        String path = filePath + fileName;
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        ossClient.getObject(new GetObjectRequest(bucketName, filepath), new File(path));
        // 关闭OSSClient。
        ossClient.shutdown();
        return path;
    }

    /**
     * oss下载文件到本地，如果是图片并压缩一半清晰度
     *
     * @param filepath filepath
     * @return {@link File}
     */
    public static File downloadFile(String filepath) {
        FileUtil.mkdir(filePath);
        String fileName = FileUtil.getName(filepath);
        //获取该文件的本地路径
        String path = filePath + fileName;
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        ossClient.getObject(new GetObjectRequest(bucketName, filepath), new File(path));
        // 关闭OSSClient。
        ossClient.shutdown();
        File file = FileUtil.file(path);
        return Opt.ofTry(()-> ysImg(file)).exceptionOrElse(null);
    }

    /**
     * 将oss图片转成byte[]数组
     *
     * @param filepath filepath
     * @return {@link byte[]}
     */
    public static byte[] getPicByte(String filepath) {
        InputStream picPathStream = getPicFile_cut(filepath);
        return Opt.ofNullable(picPathStream).map(e->IoUtil.readBytes(picPathStream)).orElse(null);
    }

    /**
     * 将oss图片转成byte[]数组
     *
     * @param filepath filepath
     * @param q 压缩量（0-100）
     * @return {@link byte[]}
     */
    public static byte[] getPicByte(String filepath,int q) {
        InputStream picPathStream = getPicFile_cut(filepath,q);
        return Opt.ofNullable(picPathStream).map(e->IoUtil.readBytes(picPathStream)).orElse(null);
    }

    /**
     * 生成压缩输入流
     *
     * @param filepath filepath
     * @return {@link InputStream}
     */
    public static InputStream getPicFile_cut(String filepath) {
        //"test/upload/2019.jpg"
        String style = "image/auto-orient,1/resize,p_40/quality,q_40";
        String objectName = filepath;

        // 创建OSSClient实例。
        OSS ossClient = getOssClient();

        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);

        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        //URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
        // 关闭OSSClient。
        ossClient.shutdown();
        URL url = ossClient.generatePresignedUrl(req);
        return Opt.ofTry(()-> url.openStream()).exceptionOrElse(null);
    }

    /**
     * 压缩图片
     *
     * @param filepath filepath
     * @param q        压缩率量（0-100）
     * @return {@link InputStream}
     */
    public static InputStream getPicFile_cut(String filepath, int q) {
        //"test/upload/2019.jpg"
        String style = "image/auto-orient,1/resize,p_" + q + "/quality,q_" + q;
        String objectName = filepath;

        // 创建OSSClient实例。
        OSS ossClient = getOssClient();

        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);

        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        //URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
        URL url = ossClient.generatePresignedUrl(req);
        // 关闭OSSClient。
        ossClient.shutdown();
        return Opt.ofTry(()-> url.openStream()).exceptionOrElse(null);
    }

    /**
     * 生成未压缩stream流
     *
     * @param filepath filepath
     * @return {@link InputStream}
     */
    public static InputStream getFileStream(String filepath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();

        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(bucketName, filepath, expiration);
        // 关闭OSSClient。
        ossClient.shutdown();
        return Opt.ofTry(()-> url.openStream()).exceptionOrElse(null);
    }

    /**
     * 生成未压缩文件
     *
     * @param group    分组，操作完后，删除
     * @param filepath filepath
     * @return {@link File}
     */
    public static File getPicFile(String group, String filepath) {
        String picPath = getFileLink(filepath);
        return Opt.ofTry(()->{
            String nowFilePath = filePath + group + "/" + FileUtils.getName(filepath);
            return HttpUtil.downloadFileFromUrl(picPath, nowFilePath);
        }).exceptionOrElse(null);
    }

    /**
     * 生成压缩文件
     *
     * @param group    分组，操作完后，删除
     * @param filepath oss图片地址
     * @param q        q压缩率
     * @return {@link File}
     */
    public static File getPicFile_q(String group, String filepath, int q) {
        String picPath = getYsPicLink_q(filepath, q);
        return Opt.ofTry(()->{
            String nowFilePath = filePath + group + "/" + FileUtils.getName(filepath);
            return HttpUtil.downloadFileFromUrl(picPath, nowFilePath);
        }).exceptionOrElse(null);
    }

    /**
     * 生成0.5倍压缩图片
     *
     * @param group    分组，操作完后，删除
     * @param filepath filepath
     * @return {@link File}
     */
    public static File getPicFileYs(String group, String filepath) {
        String picPath = getFileLink(filepath);
        File file = Opt.ofTry(() -> {
            String nowFilePath = filePath + group + "/" + FileUtils.getName(filepath);
            return HttpUtil.downloadFileFromUrl(picPath, nowFilePath);
        }).exceptionOrElse(null);
        return Opt.ofNullable(file).ifPresent(e->ysImg(file)).orElse(null);
    }

    /**
     * 按照样式压缩图片
     *
     * @param filepath filepath
     * @param style    风格
     * @return {@link String}
     */
    public static String getPicPath_Cut(String filepath, String style) {
        if (StrUtil.isEmptyIfStr(style)) {
            return getFileLink(filepath);
        }
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();

        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, filepath, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);

        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(req);

        // 关闭OSSClient。
        ossClient.shutdown();
        return url.toString();
    }

    /**
     * 压缩图片
     *
     * @param imageFile 图像文件
     * @return {@link File}
     */
    public static File ysImg(File imageFile) {
        File outFile = new File(filePath + XyUtils.getId32() + ".jpg");
        ImgUtil.compress(imageFile, outFile, 0.5f);
        return outFile;
    }


    /**
     * 压缩图片
     *
     * @param imageFile 图像文件
     * @param group     分组
     * @return {@link File}
     */
    public static File ysImg(File imageFile, String group) {
        File outFile = new File(filePath + group + "/" + XyUtils.getId32() + ".jpg");
        ImgUtil.compress(imageFile, outFile, 0.5f);
        return outFile;
    }

    /**
     * 按照百分比压缩
     *
     * @param filepath filepath
     * @param q        压缩量(0-100)
     * @return {@link String}
     */
    public static String getYsPicLink_q(String filepath, int q) {
        String style = "image/auto-orient,1/resize,p_" + q + "/quality,q_" + q;
        return getPicPath_Cut(filepath, style);
    }

    /**
     * 按照尺寸压缩 128*128
     *
     * @param filepath filepath
     * @return {@link String}
     */
    public static String getPicPath_Cut_128(String filepath) {
        String style = "image/resize,m_lfit,w_128/quality,q_100";
        return getPicPath_Cut(filepath, style);
    }

    /**
     * 按照尺寸压缩 640*640
     *
     * @param filepath filepath
     * @return {@link String}
     */
    public static String getPicPath_Cut_640(String filepath) {
        String style = "image/resize,m_lfit,w_640/quality,q_100";
        return getPicPath_Cut(filepath, style);
    }
}
